package top.huxy.boot.util.schedule;

import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.springframework.beans.BeansException;
import top.huxy.boot.BlogApiApplication;
import top.huxy.boot.config.Constant;
import top.huxy.boot.model.entity.ScheduleJob;
import top.huxy.boot.model.entity.ScheduleJobLog;
import top.huxy.boot.service.ScheduleLogService;
import top.huxy.boot.util.ExceptionUtils;
import top.huxy.boot.util.StringUtils;

import java.lang.reflect.Method;

@Slf4j
public class ScheduleRunnable implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        Object o = jobDataMap.get(Constant.TIMER_TASK_NAME);
        if (o == null) {
            log.error("任务内容为空");
            return;
        }

        //获取任务
        ScheduleJob scheduleJob = (ScheduleJob) o;

        //获取执行目标
        String beanName = scheduleJob.getBeanName();
        String methodName = scheduleJob.getMethodName();

        //参数合法化判断
        {
            String temp;
            if ((temp = StringUtils.getEmptyParamName("beanName,methodName", beanName, methodName)) != null) {
                log.error("变量" + temp + "为空");
            }
        }
        Object bean;
        try {
            bean = BlogApiApplication.app.getBean(beanName);
        } catch (BeansException e) {
            log.error("no such bean:" + beanName, e);
            return;
        }

        String arg = scheduleJob.getParam();

        Method targetMethod;

        if (StringUtils.isEmpty(arg)) {
            try {
                targetMethod = bean.getClass().getMethod(methodName);
            } catch (NoSuchMethodException e) {
                log.error("no such method:" + methodName, e);
                return;
            }
        } else {
            try {
                targetMethod = bean.getClass().getMethod(methodName, String.class);
            } catch (NoSuchMethodException e) {
                log.error("no such method:" + methodName + ",args count=1 and args type is String", e);
                return;
            }
        }
        invoke(scheduleJob, targetMethod, bean, arg);
    }


    private void invoke(ScheduleJob scheduleJob, Method method, Object target, String arg) {
        long time_start = System.currentTimeMillis();
        boolean res = true;
        Object result = null;
        StringBuilder sb = new StringBuilder();
        try {
            sb.append("准备执行任务，任务id:").append(scheduleJob.getJobId()).append("\n");

            if (StringUtils.isEmpty(arg)) {
                result = method.invoke(target);
            } else {
                result = method.invoke(target, arg);
            }

        } catch (Exception e) {
            sb.append("任务执行失败\n");
            sb.append(StringUtils.getStackTrace(e));
            log.error("执行任务失败,任务id=" + scheduleJob.getJobId());
            res = false;

            //记录异常日志
            ExceptionUtils.logError(e);
        } finally {
            long time_end = System.currentTimeMillis();
            sb.append("任务").append(scheduleJob.getJobId()).append("执行完成\n");
            sb.append("结果").append(res ? "[成功]\n" : "[失败]\n");
            sb.append("耗时").append(time_end - time_start).append("ms\n");
            if (res) {
                sb.append("执行成功返回值:\n").append(result);
                sb.append("\n");
            }

            //保存日志，待完成
            ScheduleJobLog scheduleJobLog = new ScheduleJobLog(scheduleJob.getJobId(),
                    res,
                    sb.toString(),
                    result == null ? null : result.toString(),
                    (int) (time_end - time_start),System.currentTimeMillis());
            ScheduleLogService scheduleLogService = BlogApiApplication.app.getBean(ScheduleLogService.class);

            scheduleLogService.saveLog(scheduleJobLog);
        }
    }
}
